Usage
Basic Example
import Trustchex from '@trustchex/react-native-sdk';
<Trustchex
baseUrl="https://your-api.com"
sessionId="session-123"
onCompleted={() => console.log('Done')}
onError={(error) => console.error(error)}
/>
Props
| Prop | Type | Required | Description |
|---|---|---|---|
baseUrl | string | ✅ | Your API base URL |
sessionId | string | ❌ | Session identifier |
branding | object | ❌ | Colors and logo |
locale | 'en' | 'tr' | ❌ | Language |
onCompleted | () => void | ❌ | Called when the verification process finishes |
onError | (error) => void | ❌ | Error callback |
onDocumentRead | (result: DocumentReadResult) => void | ❌ | Called when document is read (NFC or OCR) |
skipNfcResultScreen | boolean | ❌ | Skip the NFC document review screen and proceed automatically after a successful NFC scan. Default: false |
skipSuccessScreen | boolean | ❌ | Skip the final success screen and call onCompleted immediately when the process finishes. Default: false |
Document Read Event
The onDocumentRead callback fires as soon as document data is available — immediately after a successful NFC chip read or after a successful camera OCR scan. It receives a unified DocumentReadResult object regardless of source.
import Trustchex, { type DocumentReadResult } from '@trustchex/react-native-sdk';
<Trustchex
baseUrl="https://your-api.com"
sessionId="session-123"
onDocumentRead={(result: DocumentReadResult) => {
const { document } = result;
console.log(document.documentType); // "P" (passport) | "I" (ID card)
console.log(document.issuingCountry); // "DEU"
console.log(document.nationality); // "DEU"
console.log(document.documentNumber); // "C01X00T478"
console.log(document.personalNumber); // "8512310074" | null
console.log(document.lastName); // "MÜLLER"
console.log(document.firstName); // "JÜRGEN KARL"
console.log(document.sex); // "M" | "F" | "X" | "U"
console.log(document.dateOfBirth); // "1985-03-10" (ISO 8601)
console.log(document.dateOfExpiry); // "2030-11-05" (ISO 8601)
}}
onCompleted={() => console.log('Done')}
onError={(error) => console.error(error)}
/>
DocumentReadResult
interface DocumentReadResult {
document: {
documentType: string; // "P" (passport) | "I" (ID card)
issuingCountry: string; // 3-letter ICAO country code, e.g. "TUR"
nationality: string;
documentNumber: string;
personalNumber: string | null;
lastName: string; // Best available name, e.g. "MÜLLER"
firstName: string; // Best available name, e.g. "JÜRGEN"
sex: 'M' | 'F' | 'X' | 'U';
dateOfBirth: string | null; // ISO 8601, e.g. "1990-05-15"
dateOfExpiry: string | null; // ISO 8601, e.g. "2028-03-01"
};
name: {
rawLast: string; // MRZ ASCII surname
rawFirst: string; // MRZ ASCII given name
displayLast: string; // Best Unicode form, e.g. "MÜLLER"
displayFirst: string; // Best Unicode form, e.g. "JÜRGEN"
source: 'dg11' | 'reverse_table' | 'raw';
};
face?: {
data: string; // Base64-encoded image
mimeType: string; // e.g. "image/jpeg"
};
}
Name Sources
| Source | Description |
|---|---|
dg11 | Exact printed name read from the NFC chip's DG11 file (UTF-8). Highest accuracy. |
reverse_table | Reconstructed via ICAO 9303 reverse transliteration (e.g. OE→Ö, UE→Ü). Applied for known countries. |
raw | No conversion — display equals the raw MRZ ASCII value. |
Flow Control
Skip NFC Result Screen
By default, after a successful NFC chip read the SDK shows a review screen where the user can verify their document data before proceeding. Set skipNfcResultScreen to bypass this screen entirely — the SDK advances automatically as soon as the NFC scan completes.
<Trustchex
baseUrl="https://your-api.com"
sessionId="session-123"
skipNfcResultScreen
onCompleted={() => console.log('Done')}
onError={(error) => console.error(error)}
/>
Use onDocumentRead alongside this prop if you need to access the scanned document data without showing the review screen.
Skip Success Screen
By default, after the verification process completes the SDK shows a success animation for 3 seconds before calling onCompleted. Set skipSuccessScreen to call onCompleted immediately with no animation or delay.
<Trustchex
baseUrl="https://your-api.com"
sessionId="session-123"
skipSuccessScreen
onCompleted={() => {
// Called immediately when verification is complete
navigation.navigate('Home');
}}
onError={(error) => console.error(error)}
/>
Both props can be combined:
<Trustchex
baseUrl="https://your-api.com"
sessionId="session-123"
skipNfcResultScreen
skipSuccessScreen
onDocumentRead={(result) => console.log(result.name.displayFirst)}
onCompleted={() => navigation.navigate('Home')}
onError={(error) => console.error(error)}
/>
Accepted Document Types
Which documents a user may scan is set per workflow, not in the app. In the dashboard, open Workflows, edit the Identity Document Scan (or Identity Document eID Scan) step, and choose Allowed Document Types:
| Setting | What the user can scan |
|---|---|
| None selected (default) | ID card or passport |
| Identity Card | ID cards only |
| Passport | Passports only |
No SDK prop or code change is needed. The SDK reads the setting from the verification session and adapts the scan screen:
- Guide and instructions. The scan frame shows a drawing of the document to hold up, and the instruction names it ("Show the front of the card", "Show the photo page"). When both types are allowed, the guide alternates between an ID card and a passport until the document is recognised.
- Other documents are rejected on the spot. A document that isn't allowed is never captured. The user is asked for the right one instead ("Show your ID card" or "Show your passport"), and scanning continues as soon as an allowed document is shown.
- ID cards: front first. For ID cards, the front is always read before the back. Showing the back first prompts the user to turn the card over.
Allowed Countries, on the same step, limits documents by issuing country. That check runs once the document has been read: a document from another country is rejected, and the user is asked to scan again.
With these checks, a user can't complete the step with a document the workflow doesn't accept.
With Branding
<Trustchex
baseUrl="https://your-api.com"
sessionId="session-123"
branding={{
logoUrl: 'https://your-logo.png',
primaryColor: '#1E40AF',
secondaryColor: '#F8FAFC',
tertiaryColor: '#DC2626'
}}
locale="en"
onCompleted={() => console.log('Done')}
/>
Deep Links (Optional)
Deep link functionality is an optional feature if you want to publish a standalone app. To process deep links with the SDK, you need to configure deep links in your app and set up the required hooks to handle incoming URLs.
1. Configure Deep Link Schemes
iOS - Add to Info.plist:
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLSchemes</key>
<array>
<string>yourapp</string>
</array>
</dict>
</array>
Android - Add to AndroidManifest.xml. Keep android:launchMode="singleTask" so a deep link that arrives while the app is already open is delivered to the existing activity instead of starting a new one:
<activity android:name=".MainActivity" android:launchMode="singleTask">
<intent-filter android:autoVerify="true">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="yourapp" />
</intent-filter>
</activity>
2. Set Up Deep Link Handling
Import and use the handleDeepLink function to process incoming URLs:
import React from 'react';
import { AppState, Linking } from 'react-native';
import Trustchex, { handleDeepLink } from '@trustchex/react-native-sdk';
const App = () => {
const appState = React.useRef(AppState.currentState);
const [baseUrl, setBaseUrl] = React.useState<string | undefined>();
const [sessionId, setSessionId] = React.useState<string>('');
const lastHandledUrl = React.useRef<string | null>(null);
const processDeepLink = React.useCallback((url: string | null) => {
// Ignore empty URLs and re-processing the same URL (getInitialURL returns
// the last intent on every foreground, so this would otherwise re-fire).
if (!url || url === lastHandledUrl.current) return;
const [bUrl, sId] = handleDeepLink({ url });
if (bUrl && sId) {
lastHandledUrl.current = url;
setBaseUrl(bUrl);
setSessionId(sId);
}
}, []);
React.useEffect(() => {
// Cold start (app launched by the link).
Linking.getInitialURL().then(processDeepLink);
// Warm start (link arrives while the app is running).
const urlSub = Linking.addEventListener('url', ({ url }) =>
processDeepLink(url)
);
// On Android's New Architecture (bridgeless) the warm-start 'url' event can
// be dropped ("Tried to access onNewIntent while context is not ready"), so
// re-read the launch intent whenever the app returns to the foreground to
// recover it. Requires the MainActivity.onNewIntent override below.
const appStateSub = AppState.addEventListener('change', (next) => {
if (appState.current.match(/inactive|background/) && next === 'active') {
Linking.getInitialURL().then(processDeepLink);
}
appState.current = next;
});
return () => {
urlSub.remove();
appStateSub.remove();
};
}, [processDeepLink]);
return (
<Trustchex
baseUrl={baseUrl}
sessionId={sessionId}
onCompleted={() => console.log('Done')}
onError={(error) => console.error(error)}
/>
);
};
3. Native Setup (Required for Warm-Start Deep Links)
A link that arrives while the app is already open needs a small native override on each platform. Without these, the link is silently dropped and the user stays on the first screen even though the JavaScript above is correct.
Android — override onNewIntent in your MainActivity to store the fresh intent, so Linking.getInitialURL() (used by the foreground re-check above) returns the new link rather than the original launch URL:
// MainActivity.kt
import android.content.Intent
override fun onNewIntent(intent: Intent) {
setIntent(intent)
super.onNewIntent(intent)
}
iOS — forward incoming URLs to RCTLinkingManager in your AppDelegate. This is what emits the JavaScript 'url' event while the app is running:
// AppDelegate.swift
import React // exposes RCTLinkingManager
func application(
_ app: UIApplication,
open url: URL,
options: [UIApplication.OpenURLOptionsKey: Any] = [:]
) -> Bool {
return RCTLinkingManager.application(app, open: url, options: options)
}
// Universal Links (https://…):
func application(
_ application: UIApplication,
continue userActivity: NSUserActivity,
restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void
) -> Bool {
return RCTLinkingManager.application(
application, continue: userActivity, restorationHandler: restorationHandler)
}
The handleDeepLink function parses URLs with the format:
scheme://app-url/your-api.com/verification-session/session-123
And returns [baseUrl, sessionId] that you can use with the Trustchex component.
Sessions
Create sessions using the REST API.
Session Access Methods
The SDK provides multiple ways for users to access their verification session:
1. Deep Link (Recommended)
Users click a link that opens the app directly with the session:
// Deep link format: yourapp://app-url/your-api.com/verification-session/session-123
<Trustchex
baseUrl="https://your-api.com"
sessionId="session-123" // From deep link
onCompleted={() => console.log('Done')}
/>
Benefits:
- Seamless user experience - one tap to start
- Direct navigation to verification
- No manual input required
- Works great for email and SMS campaigns
2. QR Code Scanning (Recommended)
Users scan a QR code that contains the session information. The SDK includes a built-in QR scanner accessible from the welcome screen.
Benefits:
- Quick and contactless
- No typing required
- Ideal for in-person verification
- Built-in scanner included in SDK
3. Session Code Entry (Alternative)
Users can manually enter an 8-character alphanumeric code:
<Trustchex
baseUrl="https://your-api.com"
// No sessionId prop needed - user enters code manually
onCompleted={() => console.log('Done')}
/>
When no sessionId is provided, the SDK displays a screen where users can:
- Enter the 8-character session code
- Scan a QR code
Use Cases:
- Fallback when QR/deep link unavailable
- Phone/voice support scenarios
- Print media without QR capability
Creating Sessions
When creating a session via the REST API, you'll receive access methods in the response:
const response = await fetch('https://your-api.com/api/v1/verification-sessions', {
method: 'POST',
headers: { 'x-api-key': 'YOUR_API_KEY' },
body: JSON.stringify({
workflowId: 'workflow-123',
email: 'user@example.com'
})
});
const { deepLink, qrCodeLink, sessionCode } = await response.json();
// Use deepLink for direct app navigation (recommended)
// Use qrCodeLink to generate QR code (recommended)
// Use sessionCode as alternative access method